package com.example.demo.thread;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 多线程读取文件
 * 每行 数据不同的对象 并统计出各个对象的数量
 */
public class MultiThreadReadFile {

    private final static int THREAD_COUNT = 5;

    private final static String PATH = "";

    public static void main(String[] args) throws Exception {
        File file = new File(PATH);
//        long fileSize = file.length();
        long lines = Files.lines(Paths.get(file.getPath())).count();
        lines = lines + 1;

        // 线程
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
        // 创建Map数组保存线程中的统计数据
        Map<String, Integer>[] results = new Map[THREAD_COUNT];
        // 分配任务
        long blockSize = lines / THREAD_COUNT;
        for (int i = 0; i < THREAD_COUNT; i++) {
            long start = i * blockSize;
            long end = (i == THREAD_COUNT - 1) ? lines : (i + 1) * blockSize;
            // 执行任务
            executor.submit(new InnerTask(file, start, end, i, results));
        }

        executor.shutdown();
        executor.awaitTermination(10, TimeUnit.SECONDS);
        // 合并结果
        HashMap<String, Integer> finalMap = new HashMap<>();
        for (Map<String, Integer> result : results) {
            for (String key : result.keySet()) {
                Integer value = result.getOrDefault(key, 0);
                finalMap.put(key, finalMap.getOrDefault(key, 0) + value);
            }
        }
        System.out.println(finalMap);
    }

    private static class InnerTask implements Runnable {

        private final File file;
        private final long start;
        private final long end;
        private final int tableIndex;
        private final Map<String, Integer>[] results;

        public InnerTask(File file, long start, long end, int tableIndex, Map<String, Integer>[] results) {
            this.file = file;
            this.start = start;
            this.end = end;
            this.tableIndex = tableIndex;
            this.results = results;
        }

        @Override
        public void run() {
            try (FileReader fileReader = new FileReader(file);
                 LineNumberReader lr = new LineNumberReader(fileReader);
                 BufferedReader br = new BufferedReader(fileReader);
                 RandomAccessFile raf = new RandomAccessFile(file, "r");) {
                // 跳过头
//                raf.seek(start);
                Map<String, Integer> resultMap = new HashMap<>();
                String line;
                // && raf.getFilePointer() < end
                while ((line = lr.readLine()) != null) {
                    if (lr.getLineNumber() >= start && lr.getLineNumber() < end) {
                        line = line + " ";
                        String[] split = line.split("!\\^");
                        String tableName = split[0];
                        resultMap.put(tableName, resultMap.getOrDefault(tableName, 0) + 1);
                    }
                }
                results[tableIndex] = resultMap;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}